package remote

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strings"

	"gitee.com/dark.H/go-remote-repl/lpc"

	"gitee.com/dark.H/go-remote-repl/datas"

	"github.com/c-bata/go-prompt"
	"github.com/manifoldco/promptui"
)

func (api *ApiConn) SendMsg(msg string) {
	_, err := api.con.Write([]byte(msg))
	if err != nil {
		log.Println("send msg err:", err)
		api.con.Close()
	}
}

func (api *ApiConn) ReadMsg() string {
	buf := make([]byte, 4096)
	n, err := api.con.Read(buf)
	if err != nil {
		log.Println("con read msg err:", err)
		api.con.Close()
		return ""
	}
	return string(buf[:n])
}

func (api *ApiConn) Choose(choosemsg string) (string, error) {
	// list:a\nb\n
	var choose []string
	var label string
	if strings.Contains(choosemsg, SEP) {
		ss := strings.SplitN(choosemsg[5:], SEP, 2)
		label = ss[0]
		choose = strings.Split(ss[1], "\n")
	} else {
		choose = strings.Split(choosemsg[5:], "\n")
		label = "choose one"
	}
	prompt := promptui.Select{
		Label:        label,
		Items:        choose,
		HideSelected: true,
		Size:         10,
		Searcher: func(s string, ix int) bool {
			return strings.Contains(choose[ix], s)
		},
	}
	_, result, err := prompt.Run()

	if err != nil {
		fmt.Printf("Prompt failed %v\n", err)
		return "", err
	}
	return result, nil
}

func (api *ApiConn) ReplJ(jsonStr string) (string, error) {
	// fmt.Println(jsonStr)
	suggestJson := new(struct {
		Label   string            `json:"label"`
		Options map[string]string `json:"options"`
	})
	err := json.Unmarshal([]byte(jsonStr[6:]), suggestJson)
	if err != nil {
		log.Println(err)
		return "", err
	}
	if output := datas.Tui.Input(suggestJson.Label, suggestJson.Options); output != "" {
		return output, nil
	} else {
		return "", errors.New("Input illegal!!:" + jsonStr)
	}
}

func (api *ApiConn) ReplF(jsonStr string) (string, string, error) {
	// fmt.Println(jsonStr)
	suggestJson := new(struct {
		Label   string            `json:"label"`
		Options map[string]string `json:"options"`
	})
	err := json.Unmarshal([]byte(jsonStr[6:]), suggestJson)
	if err != nil {
		log.Println(err)
		return "", "", err
	}
	ks := []string{}
	for k := range suggestJson.Options {
		ks = append(ks, k)
	}
	if len(ks) > 1 {
		if output := datas.Tui.Select(suggestJson.Label, ks...); output != "" {
			return output, suggestJson.Label, nil
		} else {
			return "", "", errors.New("Input illegal!!:" + jsonStr)
		}
	} else if len(ks) == 1 {
		return ks[0] + ":" + suggestJson.Options[ks[0]], suggestJson.Label, nil
	} else {
		return "", suggestJson.Label, nil
	}

}

func (api *ApiConn) Repl(choosemsg string) (string, error) {
	// repl:a,b,
	// log.Println("==>", choosemsg)

	var recommend []string
	var label string
	if strings.Contains(choosemsg, SEP) {
		ss := strings.SplitN(choosemsg[5:], SEP, 2)
		label = ss[0]
		recommend = strings.Split(ss[1], ",")
	} else {
		recommend = strings.Split(choosemsg[5:], ",")
		label = "choose one"
	}

	if strings.Contains(choosemsg, "::file::") {

		// recommend := strings.Split(choosemsg[5:], ",")
		var ss []prompt.Suggest
		for _, t := range recommend {
			if strings.Contains(t, "::file::") {
			} else {
				ss = append(ss, prompt.Suggest{
					Text: t,
				})
			}
		}
		result := prompt.Input(label+">", func(d prompt.Document) []prompt.Suggest {
			return lpc.FilePathCompleter.Complete(d)
		})
		if state, err := os.Stat(result); err == nil {
			log.Println("load file ::", result)
			if !state.IsDir() {
				if resultbuf, err := ioutil.ReadFile(result); err == nil {
					result = strings.Join(strings.Split(string(resultbuf), "\n"), ",")
					if !strings.Contains(result, ":") {
						log.Fatal("not contains server \"domain:port\\ndomain:prot2\\n\" ")
					}
				}
			}
		}
		return result, nil
	} else {
		// recommend := strings.Split(choosemsg[5:], ",")
		completer := func(d prompt.Document) (s []prompt.Suggest) {
			for _, t := range recommend {
				s = append(s, prompt.Suggest{
					Text: t,
				})
			}
			return prompt.FilterHasPrefix(s, d.GetWordBeforeCursor(), true)
		}

		result := prompt.Input(label+">", completer)

		return result, nil
	}

}
